////////////////////////////////////////////////////////////////////////////////

#ifndef _GUI_H_
#include "gui.h"
#endif

////////////////////////////////////////////////////////////////////////////////

#ifndef _SPLASHSCREEN_H_
#include "splashscreen.h"
#endif

#ifndef _MENUSCREEN_H_
#include "menuscreen.h"
#endif

#ifndef _PLAYSCREEN_H_
#include "playscreen.h"
#endif

#ifndef _CLIENT_H_
#include "client.h"
#endif

#ifndef _THEME_H_
#include "theme.h"
#endif

#ifndef _INPUT_H_
#include "input.h"
#endif

#ifndef _TIMER_H_
#include "timer.h"
#endif

#ifndef _SETTINGS_H_
#include "settings.h"
#endif

#ifndef _PLAYERSINFO_H_
#include "playersinfo.h"
#endif

#include <stdio.h>
#include <SDL\SDL_ttf.h>
#include <SDL_mixer.h>

//////////////////////////////////////////////////////////////////////////


GUI::GUI():
    m_CurrentScreen (GUI::Splash),
    m_CurrentScreenMode (0),
    m_NeedSwitchingScreen (false)
{
    Settings::Load();
    int audio_rate = 22050;
    Uint16 audio_format = AUDIO_S16; 
    int audio_channels = 2;
    int audio_buffers = 4096;

    SDL_Init( SDL_INIT_EVERYTHING );
    TTF_Init();

    if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers)) 
    {
        throw "Unable to open audio!";
    }

    m_ScreenModes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
    if (!m_ScreenModes) 
    {
        throw "No modes available!";
    }
    if (m_ScreenModes == (SDL_Rect **)-1) 
    {
        throw "All resolutions available. Do not know what to choose.";
    }

    for(m_ScreenModeCount = 0; m_ScreenModes[m_ScreenModeCount]; ++m_ScreenModeCount);

    m_CurrentFullscreenMode = Settings::GetFullscreenMode();
    SDL_Rect *resolution = Settings::GetResolution();
    for (int i = 0; i < m_ScreenModeCount; ++i)
    {
        if ((m_ScreenModes[i]->w == resolution->w) && (m_ScreenModes[i]->h == resolution->h))
        {
            m_CurrentScreenMode = i;
            break;
        }
    }
    m_ResizeFactor = m_ScreenModes[m_CurrentScreenMode]->w;
    m_Surface = SDL_SetVideoMode(m_ScreenModes[m_CurrentScreenMode]->w, m_ScreenModes[m_CurrentScreenMode]->h, 32, (m_CurrentFullscreenMode)? (SDL_FULLSCREEN | SDL_HWSURFACE) : (0) | SDL_DOUBLEBUF);
    GUI_Theme::Reload(".\\rc", m_ResizeFactor);

    m_Screens.resize(ScreenCount);
    
    SwitchToScreen(Splash);
    DoSwitchingScreen();
    //_spawnl(
    //spawn
}


//////////////////////////////////////////////////////////////////////////


GUI::~GUI()
{
    Settings::Save();
    m_Input.RemoveObserver(m_Screens[m_PreviousScreen]);
    SDL_FreeSurface(m_Surface);
    GUI_Theme::Release();
    Mix_CloseAudio();
    TTF_Quit();
    SDL_Quit();
}


//////////////////////////////////////////////////////////////////////////


int GUI::GetCurrentScreenMode()
{
    return m_CurrentScreenMode;
}


//////////////////////////////////////////////////////////////////////////


bool GUI::GetCurrentFullscreenMode()
{
    return m_CurrentFullscreenMode;
}


//////////////////////////////////////////////////////////////////////////


SDL_Rect *GUI::GetResolution(int _mode)
{
    while (_mode < 0)
        _mode += m_ScreenModeCount;
    return m_ScreenModes[_mode % m_ScreenModeCount];
}


//////////////////////////////////////////////////////////////////////////


void GUI::Resize(int _mode, bool _fullscreen)
{
    if (_mode < 0)
        _mode += m_ScreenModeCount;
    m_CurrentScreenMode = (_mode % m_ScreenModeCount);
    m_CurrentFullscreenMode = _fullscreen;
    m_Surface = SDL_SetVideoMode(m_ScreenModes[m_CurrentScreenMode]->w, m_ScreenModes[m_CurrentScreenMode]->h, 32, (_fullscreen)? (SDL_FULLSCREEN | SDL_HWSURFACE) : (0) | SDL_DOUBLEBUF);
    m_ResizeFactor = m_ScreenModes[m_CurrentScreenMode]->w;
    GUI_Theme::Resize(m_ResizeFactor);
    m_Screens[m_CurrentScreen]->Resize();
    //m_Label->Resize();
    //m_Button->Resize();
}


//////////////////////////////////////////////////////////////////////////


Client *GUI::GetClient()
{
    return m_Client;
}


//////////////////////////////////////////////////////////////////////////


void GUI::DoSwitchingScreen()
{
    m_NeedSwitchingScreen = false;
    if (m_Screens[m_PreviousScreen])
    {
        m_Input.RemoveObserver(m_Screens[m_PreviousScreen]);
        delete m_Screens[m_PreviousScreen];
    }

    GUI_Screen *screen; 
    switch (m_CurrentScreen)
    {
    case Splash:
            screen = new GUI_SplashScreen(this);
        break;
    case Menu:
            screen = new GUI_MenuScreen(this);
        break;
    case Play:
            screen = new GUI_PlayScreen(this, m_Client);
            m_Client->StartEngine();
            m_Client->StartNetwork(Settings::GetServerAddress(), Settings::GetNickName());
        break;
    default:
        return;
        break;
    }

    m_Screens[m_CurrentScreen] = screen;
    m_Input.AddObserver(m_Screens[m_CurrentScreen]);
}


//////////////////////////////////////////////////////////////////////////


void GUI::SwitchToScreen(GUI::Screen _screen)
{
    m_PreviousScreen = m_CurrentScreen;
    m_CurrentScreen = _screen;
    m_NeedSwitchingScreen = true;
}


//////////////////////////////////////////////////////////////////////////


void GUI::Render()
{
    m_Screens[m_CurrentScreen]->Render(m_Surface);
}


////////////////////////////////////////////////////////////////////////////////


void GUI::ProcessInput()
{
    if ((m_CurrentScreen == Play) && (!m_NeedSwitchingScreen))
    {
        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->PreProcessInput();
    }

    // Process input
    m_Input.ProcessInput();

    if ((m_CurrentScreen == Play) && (!m_NeedSwitchingScreen))
    {
        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->PostProcessInput();
    }
}


////////////////////////////////////////////////////////////////////////////////


void GUI::RunGameLoop()
{
    while (m_CurrentScreen != GUI::Exit)
    {
        // Delay
        Timer::Sleep(5);

        // Render state
        Render();

        // Process input
        ProcessInput();
        if (m_NeedSwitchingScreen)
            DoSwitchingScreen();
    }
}


//////////////////////////////////////////////////////////////////////////


void GUI::SetID( int _ID )
{
    m_ID = _ID;
    if (m_CurrentScreen == Play)
    {
        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->SetID(_ID);
        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->CreateMap("glade"); // Comment this line
    }
}


//////////////////////////////////////////////////////////////////////////


void GUI::AddStateToRenderQueue( const ServerStatePacket& _packet )
{
    if (m_CurrentScreen == Play)
    {
        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->AddStateToRenderQueue(_packet);
    }
}


//////////////////////////////////////////////////////////////////////////


void GUI::CreateMap( const std::string& _mapName )
{
    if (m_CurrentScreen == Play)
    {
//        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->CreateMap(_mapName); // Uncomment this line
    }
}


////////////////////////////////////////////////////////////////////////////////


void GUI::UpdateServerStatistics( const PlayersInfo& _playersInfo )
{
    if (m_CurrentScreen == Play)
    {
        ((GUI_PlayScreen *)m_Screens[m_CurrentScreen])->UpdateServerStatistics(_playersInfo);
    }
}


//////////////////////////////////////////////////////////////////////////


void GUI::Start( Client* _client )
{
    assert(_client);
    m_Client = _client;
    RunGameLoop();
}


//////////////////////////////////////////////////////////////////////////
